using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Security;

namespace LinqToOwin
{
  public sealed class LinqToOwinContext : IOwinContext, IResponsePathBase
  {
    public IOwinContext OwinContext
    {
      get
      {
        return context;
      }
    }

    public IOwinRequest Request
    {
      get
      {
        return context.Request;
      }
    }

    public IOwinResponse Response
    {
      get
      {
        return context.Response;
      }
    }

    public PathString ResponsePathBase
    {
      get;
      set;
    }

    public IAuthenticationManager Authentication
    {
      get
      {
        return context.Authentication;
      }
    }

    public IDictionary<string, object> Environment
    {
      get
      {
        return context.Environment;
      }
    }

    public TextWriter TraceOutput
    {
      get
      {
        return context.TraceOutput;
      }
      set
      {
        context.TraceOutput = value;
      }
    }

    public Task Completion
    {
      get
      {
        Contract.Ensures(Contract.Result<Task>() != null);

        return completion;
      }
    }

    public bool Handled
    {
      get;
      internal set;
    }

    internal bool SetHandledUponNotification
    {
      get;
      set;
    }

    internal bool? FirstResponseIsXml
    {
      get;
      set;
    }

    private readonly IOwinContext context;
    private readonly Task completion;

    internal LinqToOwinContext(IOwinContext context, Task completion)
    {
      Contract.Requires(context != null);
      Contract.Requires(completion != null);

      this.context = context;
      this.completion = completion;

      SetHandledUponNotification = true;
    }

    [ContractInvariantMethod]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
    private void ObjectInvariant()
    {
      Contract.Invariant(context != null);
      Contract.Invariant(completion != null);
    }

    public T Get<T>(string key)
    {
      return context.Get<T>(key);
    }

    public IOwinContext Set<T>(string key, T value)
    {
      return context.Set(key, value);
    }

    public T NotHandled<T>(T response)
    {
      SetHandledUponNotification = false;

      return response;
    }
  }
}